package com.chen.project.white_jotter.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.annotation.Resource;

@Configuration
@EnableWebSecurity  // 开启web安全，这个注解，我测试的结果是不加也可以。。。
@EnableGlobalMethodSecurity(prePostEnabled = true)//保证post之前的注解可以使用
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource
    private SiteProps siteProps;

    @Resource
    JWTAuthenticationEntryPoint jwtAuthenticationEntryPoint;
    @Resource
    JWTAuthorizationTokenFilter authenticationTokenFilter;

    // 用户认证服务
    @Resource
    private UserDetailsService userDetailsService;

    // 密码加密器
    @Resource
    PasswordEncoder passwordEncoder;

    // 改用 jwt
    // @Resource
    // private DataSource dataSource;
    // @Autowired
    // private PersistentTokenRepository tokenRepository;

    // 配置认证
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        // 设置处理认证的 UserDetailsService
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
    }

    // 配置授权
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        // jwt过滤器的异常处理器
        http.exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint);

        // 配置表单登录
        http.formLogin()
                // 配置登陆页面
                // 可以是 static 目录下的一个 html，也可以是一个 controller （controller内部再跳转到登陆页面）, 也可以使用另一个网站的页面作为登陆页面
                .loginPage(siteProps.getFrontAddress() + "/login")
                // 配置处理登录请求的URL，登陆表单的提交地址必须和这个URL相同
                // 原来那个 /api/login接口就废掉吧，不需要了
                .loginProcessingUrl("/api/login")
                // 配置登录成功后跳转URL
                .successForwardUrl("/api/loginSuccessfully");

        // 配置登出
        http.logout()
                .logoutUrl("/api/logout")
                .logoutSuccessUrl("/api/logoutSuccessfully");

        // 授权，认证请求
        http.authorizeRequests()
                // OPTIONS请求作为匿名用户
                .antMatchers(HttpMethod.OPTIONS, "/**").anonymous()
                // 登陆请求，登出成功的请求，所有人都可以访问
                .antMatchers("/api/login", "/api/logoutSuccessfully", "/api/register").permitAll()
                // 图片资源所有人可以访问
                .antMatchers("/api/file/**").permitAll()
                // 其他请求必须通过认证才能访问
                .antMatchers("/api/**").hasAnyRole("admin", "normal");

        // 不使用也不生产session
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        // 把 jwt 过滤器添加到 Security 过滤器链
        http.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);

        // // 改用 jwt
        // http.rememberMe()
        //         .tokenRepository(tokenRepository)
        //         .rememberMeParameter("rememberMe")
        //         .tokenValiditySeconds(604800)
        //         .userDetailsService(userDetailsService);

        // 配置关闭 csrf 防护
        http.csrf().disable();
        http.cors();
    }

    // 密码编码器，必须要注册，因为SpringSecurity内部使用PasswordEncoder做密码校验
    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    // 改用jwt
    // // 使用 JDBC 持久化 remember-me 的 token 到数据库
    // @Bean
    // public PersistentTokenRepository getPersistentTokenRepository(){
    //     // JDBC 持久化 token 到数据库
    //     JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
    //     // 配置数据源
    //     jdbcTokenRepository.setDataSource(dataSource);
    //     // 自动在数据库中建表，表中存储token等数据
    //     // 这行代码在程序第一次启动就会执行此操作，但之后重启不能再执行这行代码
    //     // jdbcTokenRepository.setCreateTableOnStartup(true);
    //     return jdbcTokenRepository;
    // }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}